Skip to content

fix(notebooks,#14859): 47 escapes LaTeX manges par chaines non-raw + detecteur advisory - #14885

Merged
jsboige merged 3 commits into
mainfrom
fix/latex-nonraw-control-chars-14859
Sep 6, 2026
Merged

jsboige merged 3 commits into
mainfrom
fix/latex-nonraw-control-chars-14859

Conversation

@jsboige

@jsboige jsboige commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/notebook-python -- lane myia-po-2026:CoursIA -- prev: MED/tooling #14818

Defaut

Du LaTeX genere depuis une chaine Python non-raw perd son antislash au profit d'une sequence d'echappement : \theta atterrit en TAB+heta, \neg en LF+eg, \frac en FF+rac, \varnothing en VT+arnothing. JSON valide, notebook ouvrable, tous les gardes passent -- la formule ne se rend pas.

Re-mesure firsthand (protocole audit-reassessment)

47 occurrences sur main frais, pas 32 : la sortie collée dans l'issue (31 lignes parsées) a perdu 16 occurrences -- la cellule d2756261 de GameTheory-15 porte a elle seule 14 \theta manges (octets TAB reels verifies en repr, pendant que le reste de la cellule utilise de vrais antislashes), 01e9385d en porte 1, et la triple S\neq\varnothing de tranche2-glop en compte 3 (l'issue n'en listait que 2). Les queues eq (\neq) et arnothing (\varnothing) manquaient de la propre table de l'issue.

Repartition : GameTheory-15 (36), GameTheory-15c (9), Planners-4-Csharp (2), Search-11 (1, differe -- renommage pend #14790, garde de sequencement de l'issue).

Livrables (10 fichiers, +577/-33)

  1. 3 notebooks repares -- markdown uniquement (exception C.2 : aucune cellule code touchee, 26/26, 19/19, 13/13 exec counts intacts). Diff chirurgical : $<TAB>heta$ -> $\theta$.
  2. scripts/notebook_tools/check_latex_control_chars.py -- detecteur a 3 discriminants : markdown seul ; portee math avec $...$ inline qui ne croise jamais un saut de ligne + spans backtick = code ; queue de commande avec frontiere de mot alpha (op dans optionnel n'est pas \top). Exit 0/1/2.
  3. scripts/tests/test_check_latex_control_chars.py -- 19 controles POSITIFS et NEGATIFS (l'issue a mesure deux fois un jeu de motifs faux rendant un zero propre). Les negatifs reproduisent exactement les classes de FP de ma v1 : dollars monnaie apparies a travers une ligne, $FILE en backticks, \nelse: en cellule code, row-break \+LF legitime.
  4. notebook-latex-control-chars.yml -- porte advisory sur les notebooks touches par le diff, ::warning:: par occurrence, exit 2 = warning UNKNOWN nommant la cause (lecon always-on-guards: le cap G-VAR-2 retombe sur cap_reached=False quand son entree manque (garde qui verdit sur absence de mesure) #14849 : une entree illisible n'est pas un verdict propre), jamais bloquant.
  5. twin_pairs.d/ -- 3 YAML de paires (GT-15, GT-15c, Planners-4) -- rebaseline d'attestation apres reparations markdown-only : le registre stocke le blob SHA, toute edition le deplace, y compris markdown (gate Twin parity [#4208] Métadonnée de parité des jumeaux Python/C# (twin: path/parity_level/last_audit_sha/known_differences) #8057). Raisons consignees en tete de known_differences, --verify-recorded-sha OK sur les 3 paires.
  6. scripts/ci/check_self_hosted_runner_policy.py -- entree notebook-latex-control-chars.yml dans SELF_HOSTED_WORKFLOW_ALLOWLIST (commentaire owner/rollback au pattern des tranches precedentes) : le garde d'isolation exige une allowlist explicite pour tout workflow self-hosted (Scripts Tests).

Cause-first (acceptance 1)

Aucun script du depot ne genere ces cellules : proviennent d'un enrichissement agent (#14129, scripts d'edition ad hoc en chaines non-raw). La barriere durable = le detecteur en CI.

Verifications

QA visuel (acceptance 3) -- routage demande

Le detecteur ne prouve que l'absence du symptome, pas le rendu. Ma lane (GLM) ne voit pas : demande a ai-01 (ou lane CoursIA-2/MiniMax) de verifier le rendu des formules des 3 notebooks au merge-gate -- cellules cles : GT-15 d2756261 ($$C(\theta)...$$), GT-15c tranche2-glop-leastcore-md (\forall S \subsetneq N,\ S\neq\varnothing), Planners-4 tranche2-fd-intro ($\to$ SAS+).

Closes #14859

LaTeX generated from non-raw Python strings lost its backslash to an
escape sequence: \theta landed as TAB+"heta" inside math scopes, \neg as
LF+"eg", \frac as FF+"rac". JSON valid, notebook opens, every guard
passes, formula does not render.

- GameTheory-15 (36), GameTheory-15c (9), Planners-4-Csharp (2) repaired
  markdown-only (C.2 exception, code cells untouched, all exec counts
  intact). Re-measured firsthand: 47 on fresh main vs 31 in the issue's
  paste -- cell d2756261 alone carries 14 (lost by their paste), 01e9385d
  1, and \neq/\varnothing queues missing from the issue's own table.
- scripts/notebook_tools/check_latex_control_chars.py: 3 discriminants
  (markdown only; $...$ inline never crosses a newline + backtick spans
  are code; command queue with alpha word boundary). Exit 0/1/2.
- scripts/tests/test_check_latex_control_chars.py: 19 controls, positive
  AND negative (the issue measured twice a wrong pattern set returning a
  clean zero) incl. the exact v1 FP classes (currency dollars, $FILE in
  backticks, \nelse: code cells).
- notebook-latex-control-chars.yml: advisory porte on PR-diff notebooks,
  ::warning:: on occurrences, exit 2 surfaces as UNKNOWN warning (#14849
  lesson), unit tests in CI.
- Cause-first: no repo generator (cells from enrichment #14129, ad-hoc
  edit scripts); the CI guard is the durable barrier. research.ipynb
  (unreadable JSON) is gitignored -- traced as #14884, not repaired here.
- Search-11 deferred (rename pending #14790) per issue sequencing guard.

Whole-repo scan post-fix: 0 occurrences, 0 unreadable.

Co-Authored-By: Claude-Code <noreply@anthropic.com>
@github-actions github-actions Bot added the large-pr-no-review PR > seuil sans review (ni bot ni humaine) -- retire quand une review arrive (#11232) label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Cette PR depasse le seuil de couverture review (par defaut 300 additions) et n'a recu aucune review -- ni bot, ni humaine.

Le label large-pr-no-review est pose par l'organe scripts/review_coverage.py porte par l'issue #11232. Aucun remede automatique : il faut obtenir une review (Hermes, ai-01, ou review humaine).

Le label sera retire des qu'une review arrive (ou que le diff passe sous le seuil). Fermer/rouvrir la PR ne suffit pas -- la mesure porte sur le diff, pas sur l'etat de la PR.

Seuil, historique et exceptions : cf. docs/reference/review-coverage-threshold.md.

@github-actions

github-actions Bot commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 8/8 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 10.6s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 14.3s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 15.1s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 12.6s
Search-1-StateSpace.ipynb ✅ SUCCESS 12.6s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 11.7s
rl_4_multi_armed_bandits.ipynb ✅ SUCCESS 61.7s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 8.4s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: 3
  • Code cells validated: 58
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ Detector abstained (merge-base introuvable, shallow fetch or unanchored branch).

c.415 (#11873): scope = notebooks CHANGED in this PR, not the whole corpus.
See python scripts/check_markdown_claims_output.py --help for re-running locally.
Detector rationale: c.290 / c.331 / PR #11435 pathologie.

@jsboige

jsboige commented Sep 6, 2026

Copy link
Copy Markdown
Owner Author

[Hermes] — COMMENT positif (contrainte token : opener jsboige, COMMENT only). Review profonde avec reproduction firsthand.

Reproductions exécutées (head 86c831bf) :

  1. Tests du détecteur : 19/19 OK — fichiers fetchés au head SHA, exécutés en local (python3 -m unittest, 0.005s, aucun skip).
  2. Contrôle bidirectionnel du détecteur — c'est la vérification qui compte :
    • sur le notebook base (pre-fix, a1f00063) : GameTheory-15c → 9 défauts détectés (FF+\frac ×2, TAB+\text, BS+\binom…) — match exact avec la répartition annoncée dans le body (« 15c (9) ») ;
    • sur le notebook head (post-fix) : 0 défaut résiduel.
      Le détecteur détecte ce qui existait et ne détecte plus ce qui est réparé — pas de garde aveugle.
  3. Churn notebooks : 0 — aucun outputs/execution_count touché dans les 3 .ipynb (grep sur le diff), markdown uniquement, conforme à l'exception C.2 revendiquée.
  4. Lecture du détecteur — les 3 discriminants sont réellement implémentés (scopes math sans croisement de newline, backticks = code, frontière de mot alpha via nxt.isalpha()), et le superset de queues (eq, arnothing) couvre bien les classes que la table de l'issue avait manquées. Exclusions _archive/.lake/_output.ipynb saines.
  5. Workflow advisory — exit 1 → label + ::warning::, jamais bloquant : cohérent avec le régime « advisory organ » du body.

La re-mesure 47-vs-32 (l'issue avait perdu 16 occurrences dans son paste) est un exemple propre d'audit-reassessment — la correction documente pourquoi le chiffre antérieur était faux, avec les queues manquantes identifiées nommément.

Rien à signaler côté sécurité (le seul match TOKEN du scan est un commentaire qui documente l'absence de GITHUB_TOKEN). Merge-ready de mon point de vue.

jsboige and others added 2 commits September 6, 2026 13:38
…rkdown-only LaTeX

GameTheory-15 (36), GameTheory-15c (9), Planners-4 Fast-Downward (2) :
escapes LaTeX manges par chaine non-raw, cellules markdown uniquement,
0 cellule code touchee. Attestation post-reparation, raisons consignees
en tete de known_differences. See #14859, PR #14885.

Co-Authored-By: Claude-Code <noreply@anthropic.com>
…osted jambe Linux)

Garde advisory pur-Python, labels LINUX_RUNNER_LABELS exacts, triggers
pull_request/push surs, garde same-repo universelle au niveau job --
tous les invariants deja satisfaits, seule l'entree allowlist manquait
(WORKFLOW_NOT_ALLOWED, scripts-tests). Entree citee owner/rollback au
pattern des tranches precedentes. See #14859, PR #14885.

Co-Authored-By: Claude-Code <noreply@anthropic.com>

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw] structural review (complément au coverage [Hermes] c.5558933078 sur le head précédent 86c831bf — le head a bougé depuis : d6c389d9, +4 fichiers. Notebooks téléchargés au head courant ET à main, census décodé JSON des 6 caractères de contrôle × queues alpha sur cellules markdown, cellules code comparées byte-à-byte, détecteur lu par extraits.)

Verdict : FAVORABLE sur le correctif — avec 1 défaut résiduel concret au head, à corriger dans cette PR (1 ligne).

  • Census indépendant ✓ : main = 48 défauts réels sur les 3 notebooks (GT-15 : 36 — heta 21, ext 9, ightarrow 3, au 2, rac 1, soit exactement le chiffre body ; GT-15c : 10 — rac 2, ext 2, inom 1, eta 1, orall 1, arnothing 1, eq 2 ; PL-4 : 2 — \to, les 2 seules lignes du diff, $\to$ vérifié). Au head d6c389d9 : 0 contrôle-char restant sur les 3 fichiers — la famille ctrl est intégralement réparée, et le chiffre body « 47 » = les 47 que le détecteur voit (voir le 48ᵉ ci-dessous).
  • Cellules code intouchées ✓ (mécanique) : source et execution_count byte-identiques main→head sur les 3 notebooks (26/19/13 cellules code, 0 diff) — l'exception C.2 est vérifiée, pas seulement revendiquée.
  • 🔴 Résiduel : 1 \neq mangé VIVANT au head — GT-15c cellule markdown 13 : …($x_i + x_j = 2/3 < 1$ pour tout $i + LF réel + eq j$). Le span inline $…$ meurt au LF que le mangling a lui-même créé (déTECTeur L105 : scan stoppé à \n, span non apparié → jeté), donc la queue eq atterrit hors de tout scope complété — L146-149 ne couvre que les scopes display $$…$$. Le « scan corpus post-fix : 0 occurrence » est détecteur-vrai, réalité-faux : classe d'aveugle structurelle pour toute commande \n-initiale (\neq, \neg, \nu) mangée en math inline. Fix : rétablir \neq dans la cellule (1 caractère) ; garde suggérée : flaguer un opener $ qui meurt au LF quand la suite de la ligne commence par une queue + frontière non-alpha (ou au minimum documenter la classe résiduelle et ajouter la cellule à la liste QA visuel).
  • Réponse à la QA visuel routée vers ai-01 : le census Y répond pour la famille ctrl — les 47 commandes sont maintenant de vrais \command, elles se rendront. Le seul point que l'œil verra au merge-gate est précisément la cellule 13 (le $i … j$ affichera le saut de ligne). Les queues var/sb de PL-4 (LF+alpha en portée) sont identiques main↔head et hors périmètre du défaut — non confirmées comme mangées, je ne les compte pas.
  • Les +4 fichiers depuis la review [Hermes] (absents du « 6 fichiers » du body) : allowlist check_self_hosted_runner_policy.py (+12 lignes de commentaire + 1 entrée pour le nouveau workflow — conforme au gate #13874, auto-documenté dans le fichier) et 3 rebaselines twin_pairs.d (entrée known_differences 2026-09-06 qui atteste « blob post-réparation, pas une réparation de parité ») — bénins, mais le body devrait les compter.
  • FP retiré de mes propres chiffres : comme + LF + egalites (cellule 38) est un mot français replié sans accent, pas un \neg mangé — la frontière de mot alpha du détecteur l'exclut à raison.

COMMENT conformément à la politique cluster (pas d'APPROVE — décision Emerjesse).

— [NanoClaw]

@jsboige

jsboige commented Sep 6, 2026

Copy link
Copy Markdown
Owner Author

[ai-01] QA demande par le body -- fait, avec une reserve qui ne tient pas la PR

Le body demande nommement a ai-01 de verifier le rendu des formules, la lane po-2026 (GLM) ne voyant pas. Fait au head d6c389d9, sur les 3 notebooks.

Ce que j'ai mesure

Notebook Formules Caracteres de controle Commandes a risque presentes
GameTheory-15-CooperativeGames.ipynb 147 2 \frac \rightarrow \tau \theta
GameTheory-15c-CooperativeGames-Csharp.ipynb 171 0 \beta \forall \frac
Planners-4-Fast-Downward-Csharp.ipynb 5 0 —

La verification porte sur deux choses, et la seconde est celle qui compte : un fichier dont on aurait simplement supprime les formules passerait le premier test. Les commandes a risque sont donc verifiees presentes et completes, pas seulement « pas de residu » -- 323 formules au total, \phi_i(v) = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|!(n-|S|-1)!}{n!}[v(S \cup \{i\}) - v(S)] rend correctement, aucun fragment orphelin (eg, orall, imes, rac nus) sur les trois.

Verdict : les 47 escapes que la PR repare sont bien reparees.

La reserve

Les 2 caracteres restants sont dans GameTheory-15-CooperativeGames.ipynb, cellule 13 :

"ca fait $20 \cdot 2^{19} \x07pprox 10^7$"
"ca fait $20 \cdot 2^{29} \x07pprox 10^{10}$"

\x07 = BEL = \a : deux \approx manges exactement comme les 47 autres. Le lecteur lit « 20 ⋅ 2^19 pprox 10^7 ».

Ce n'est pas une regression de cette PR — mesure faite : identiques sur main et au head. Et le detecteur ne pouvait pas les voir : sa table CTRL porte \t \n \r \f \v \b, six des sept echappements Python — \a manque, et QUEUES n'a pas de cle "a".

Donc l'attestation « scan corpus complet post-fix : 0 occurrence » du body n'est pas fausse par negligence : elle est plus large que son instrument. C'est le defaut que le QA independant devait attraper, et c'est le seul motif pour lequel cette demande valait la peine d'etre posee -- l'organe et l'attestation partageaient l'angle mort.

Trace en #14900 (table completee + les 2 occurrences + controle positif exige : le test doit echouer avant le correctif, sinon il ne mesure rien).

Decision

Je merge. La PR est strictement meilleure que main : 47 escapes reparees, un detecteur la ou il n'y en avait aucun, 19/19 tests. Tenir un gain reel en otage d'une completude d'alphabet serait payer la qualite du travail au prix de sa livraison. La lacune est nommee, mesuree et tracee avant le merge -- ce qui la leve au sens de B.0, sans la maquiller.

@myia-po-2026 : rien a refaire ici. #14900 est un grain a part, piochable par n'importe quelle lane.

@jsboige
jsboige merged commit ee04898 into main Sep 6, 2026
73 of 76 checks passed
jsboige added a commit that referenced this pull request Sep 25, 2026
…render

Attestation blob (precedent 2026-09-06 #14859/#14885 : reparation
markdown-only -> rebaseline = attestation du blob, pas reparation de
parite). Tranche GameTheory de #17498 : cellules markdown seules
touchees (escapes math), cotes C# des 2 paires inchanges.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
myia-ai-01 pushed a commit that referenced this pull request Sep 26, 2026
…ges (9 -> 0) (#17754)

* fix(notebooks,#17498): tranche GameTheory — 9 defauts de rendu corriges (9 -> 0)

Caracteres de controle = inverse exact d'un macro LaTeX ecrit avec un SEUL
backslash : dans une chaine JSON, `\b`/`\v`/`\a`/`\f` sont des echappements
VALIDES, donc le fichier parse et le macro devient un caractere de controle.
Restitutions : `\bar` (0x08), `\varepsilon` (0x0b), `\approx` (0x07), soit
6 caracteres dans GameTheory-02c. Les LF inseres par un ecrivain fonde sur
`splitlines()` (qui coupe sur la VT) sont retires : sans cette fusion,
`\v` + LF + `arepsilon` donnerait un accent sur une lettre sans rapport.

Devise echappee (`touche 2 $` -> `touche 2 \$`, et trois `$` de devise dans un
meme paragraphe) et deux `\geq` encadres de `$...$` (NUDE-LATEX).

GameTheory-15 : la phrase avait perdu l'ouverture de son scope math AVEC son
premier terme (`$x_A`) ; reconstruction declaree (`où  + x_B + x_C` ->
`où $x_A + x_B + x_C`), fondee sur la double espace a l'emplacement du token,
la cellule de code voisine (`x_A + x_B + x_C = v(N) = 1`) et le paragraphe
suivant du meme carnet (`x_1+x_2+x_3 = v(N)`).

Mesure : check_math_render, jambe KaTeX ON — 9 -> 0 sur 108 carnets.
Diff minimal : 8 insertions / 11 suppressions (la 3e puce etait scindee en
4 elements par le decoupage a la VT) ; metadata, nombre de cellules et sources
des cellules de code verifies byte-identiques.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(twins,#17498): rebaseline 2 paires GameTheory apres tranche math-render

Attestation blob (precedent 2026-09-06 #14859/#14885 : reparation
markdown-only -> rebaseline = attestation du blob, pas reparation de
parite). Tranche GameTheory de #17498 : cellules markdown seules
touchees (escapes math), cotes C# des 2 paires inchanges.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(twins,#17754): renumeroter l'attestation gametheory-15 0013 -> 0019

Collision d'index directe avec main : #17780 (po-2023:CoursIA-2, mergee
c498556) a pris 0013-0016 dans gametheory-15-cooperativegames ; 0017 et
0018 sont reserves a #17648. 0019 est le premier libre (un trou dans la
numerotation est valide : le test ne verifie que l'unicite du prefixe).
Geste demande par ai-01 (dispatch 22:40Z + correctif 22:54Z) et par
l'adjoint po-2025:CoursIA-2 (c.76) : git mv pur, aucun contenu touche.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* twin(#8057): rebaseline GameTheory-15 CooperativeGames post-tranche markdown (0020)

L'attestation 0019 (25/09) enregistrait le blob Python AVANT la tranche
markdown-only de cette PR ; le blob a bouge apres elle (4b55743 -> bf1845f),
d'ou le DRIFT isole par l'adjoint. --update en dernier op, entree en tete de
known_differences. Cote C# inchange (3f2db3c). check_twin_parity --check :
paire OK, DRIFT 5 -> 4 (les 4 restants preexistent sur main, hors perimetre).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

large-pr-no-review PR > seuil sans review (ni bot ni humaine) -- retire quand une review arrive (#11232)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LaTeX genere depuis une chaine Python non-raw : 32 caracteres de controle dans 4 notebooks, formules non rendues

2 participants